{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "bebe7615-3bc3-492b-ae3b-dba99003c2e0",
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import Any, Mapping, Iterable, Iterator, Tuple\n",
    "\n",
    "from trustfall import (\n",
    "    Adapter, Context, FrontendError, \n",
    "    ParseError, Schema, QueryArgumentsError,\n",
    "    ValidationError, execute_query,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "9f99495e-4e0a-4fb9-a8a2-6030249c1e8f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "number_names = [\n",
    "    \"zero\", \"one\", \"two\", \"three\", \"four\", \n",
    "    \"five\", \"six\", \"seven\", \"eight\", \"nine\", \"ten\",\n",
    "]\n",
    "\n",
    "Vertex = int\n",
    "\n",
    "class NumbersAdapter(Adapter[Vertex]):\n",
    "    def resolve_starting_vertices(\n",
    "        self,\n",
    "        edge_name: str,\n",
    "        parameters: Mapping[str, Any],\n",
    "        *args: Any,\n",
    "        **kwargs: Any,\n",
    "    ) -> Iterable[Vertex]:\n",
    "        print(\"resolve_starting_vertices call with input:\", edge_name, parameters)\n",
    "        try:\n",
    "            max_value = parameters[\"max\"]\n",
    "            yield from range(0, max_value)\n",
    "        except Exception as e:\n",
    "            print(\"resolve_starting_vertices error\", e)\n",
    "            raise\n",
    "    \n",
    "    def resolve_property(\n",
    "        self,\n",
    "        contexts: Iterator[Context[Vertex]],\n",
    "        type_name: str,\n",
    "        property_name: str,\n",
    "        *args: Any,\n",
    "        **kwargs: Any,\n",
    "    ) -> Iterable[Tuple[Context[Vertex], Any]]:\n",
    "        print(\"resolve_property call with input:\", type_name, property_name)\n",
    "        try:\n",
    "            for context in contexts:\n",
    "                vertex = context.active_vertex\n",
    "                value = None\n",
    "                if vertex is not None:\n",
    "                    if property_name == \"value\":\n",
    "                        value = vertex\n",
    "                    elif property_name == \"name\":\n",
    "                        value = number_names[vertex]\n",
    "                    else:\n",
    "                        raise NotImplementedError()\n",
    "\n",
    "                yield (context, value)\n",
    "        except Exception as e:\n",
    "            print(\"resolve_property error\", e)\n",
    "            raise   \n",
    "    \n",
    "    def resolve_neighbors(\n",
    "        self,\n",
    "        contexts: Iterator[Context[Vertex]],\n",
    "        type_name: str,\n",
    "        edge_name: str,\n",
    "        parameters: Mapping[str, Any],\n",
    "        *args: Any,\n",
    "        **kwargs: Any,\n",
    "    ) -> Iterable[Tuple[Context[Vertex], Iterable[Vertex]]]:\n",
    "        print(\"resolve_neighbors call with input:\", type_name, edge_name, parameters)\n",
    "        try:\n",
    "            for context in contexts:\n",
    "                vertex = context.active_vertex\n",
    "                neighbors = []\n",
    "                if vertex is not None:\n",
    "                    if edge_name == \"multiple\":\n",
    "                        if vertex > 0:\n",
    "                            max_value = parameters[\"max\"]\n",
    "                            neighbors = range(2 * vertex, max_value * vertex + 1, vertex)\n",
    "                    elif edge_name == \"predecessor\":\n",
    "                        if vertex > 0:\n",
    "                            neighbors = [vertex - 1]\n",
    "                    elif edge_name == \"successor\":\n",
    "                        neighbors = [vertex + 1]\n",
    "                    else:\n",
    "                        raise NotImplementedError()\n",
    "\n",
    "                yield (context, neighbors)\n",
    "        except Exception as e:\n",
    "            print(\"resolve_neighbors error\", e)\n",
    "            raise\n",
    "    \n",
    "    def resolve_coercion(\n",
    "        self,\n",
    "        contexts: Iterator[Context[Vertex]],\n",
    "        type_name: str,\n",
    "        coerce_to_type: str,\n",
    "        *args: Any,\n",
    "        **kwargs: Any,\n",
    "    ) -> Iterable[Tuple[Context[Vertex], bool]]:\n",
    "        raise NotImplementedError()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "dbcfe2e1-7384-4777-b1c7-c9abd1175f96",
   "metadata": {},
   "outputs": [],
   "source": [
    "adapter = NumbersAdapter()\n",
    "with open(\"./numbers.graphql\") as f:\n",
    "    schema = Schema(f.read())\n",
    "\n",
    "def execute(query, args):\n",
    "    return list(execute_query(adapter, schema, query, args))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "78c81e1e-534f-4ace-a651-9257c9beaedc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "resolve_property call with input: Number value\n",
      "resolve_property call with input: Number name\n",
      "resolve_starting_vertices call with input: Number {'max': 10}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[{'name': 'zero', 'value': 0},\n",
       " {'name': 'one', 'value': 1},\n",
       " {'name': 'two', 'value': 2},\n",
       " {'name': 'three', 'value': 3},\n",
       " {'name': 'four', 'value': 4},\n",
       " {'name': 'five', 'value': 5},\n",
       " {'name': 'six', 'value': 6},\n",
       " {'name': 'seven', 'value': 7},\n",
       " {'name': 'eight', 'value': 8},\n",
       " {'name': 'nine', 'value': 9}]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "query = \"\"\"\n",
    "{\n",
    "    Number(max: 10) {\n",
    "        value @output\n",
    "        name @output\n",
    "    }\n",
    "}\n",
    "\"\"\"\n",
    "args = {}\n",
    "execute(query, args)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "42c7994d-8ea6-457e-a472-2b68ad1e8f1a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "resolve_property call with input: Number value\n",
      "resolve_property call with input: Number value\n",
      "resolve_neighbors call with input: Number multiple {'max': 3}\n",
      "resolve_starting_vertices call with input: Number {'max': 4}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[{'mul': 2, 'value': 1},\n",
       " {'mul': 3, 'value': 1},\n",
       " {'mul': 4, 'value': 2},\n",
       " {'mul': 6, 'value': 2},\n",
       " {'mul': 6, 'value': 3},\n",
       " {'mul': 9, 'value': 3}]"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "query = \"\"\"\n",
    "{\n",
    "    Number(max: 4) {\n",
    "        value @output\n",
    "        \n",
    "        multiple(max: 3) {\n",
    "            mul: value @output\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\"\"\"\n",
    "args = {}\n",
    "execute(query, args)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "5a42823b-153c-4074-8408-0c094eea9fb9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "resolve_property call with input: Number value\n",
      "resolve_property call with input: Number value\n",
      "resolve_starting_vertices call with input: Number {'max': 4}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[{'value': 3}]"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "query = \"\"\"\n",
    "{\n",
    "    Number(max: 4) {\n",
    "        value @output @filter(op: \">\", value: [\"$bound\"])\n",
    "    }\n",
    "}\n",
    "\"\"\"\n",
    "args = {\n",
    "    \"bound\": 2,\n",
    "}\n",
    "execute(query, args)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "e87dcea4-731e-4c4e-9d7d-ead536f183b4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Input is not valid GraphQL:  --> 1:1\n",
      "  |\n",
      "1 | this isn't GraphQL\n",
      "  | ^---\n",
      "  |\n",
      "  = expected executable_definition\n"
     ]
    }
   ],
   "source": [
    "query = \"this isn't GraphQL\"\n",
    "args = {}\n",
    "try:\n",
    "    execute(query, args)\n",
    "    assert(False)\n",
    "except ParseError as e:\n",
    "    print(e)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "67ead102-4bcf-4c5d-8c0b-da8be876eaa1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The referenced path does not exist in the schema: [\"Number\", \"nonexistent\"]\n"
     ]
    }
   ],
   "source": [
    "query = \"\"\"\n",
    "{\n",
    "    Number(max: 4) {\n",
    "        nonexistent @output\n",
    "    }\n",
    "}\n",
    "\"\"\"\n",
    "args = {}\n",
    "try:\n",
    "    execute(query, args)\n",
    "    assert(False)\n",
    "except ValidationError as e:\n",
    "    print(e)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "50e27672-f720-433c-8bf1-3899d0869247",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Multiple fields are being output under the same name: DuplicatedNamesConflict { duplicates: {\"value\": [(\"Number\", \"value\"), (\"Number\", \"value\")]} }\n"
     ]
    }
   ],
   "source": [
    "query = \"\"\"\n",
    "{\n",
    "    Number(max: 4) {\n",
    "        value @output\n",
    "        value @output\n",
    "    }\n",
    "}\n",
    "\"\"\"\n",
    "args = {}\n",
    "try:\n",
    "    execute(query, args)\n",
    "    assert(False)\n",
    "except FrontendError as e:\n",
    "    print(e)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "9cd29b28-87d4-4fcb-a868-49e364832b91",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Multiple argument errors: [\n",
      "  One or more arguments required by this query were not provided: [\"bound\"];\n",
      "  One or more of the provided arguments are not used in this query: [\"not_bound\"];\n",
      "]\n"
     ]
    }
   ],
   "source": [
    "query = \"\"\"\n",
    "{\n",
    "    Number(max: 4) {\n",
    "        value @output @filter(op: \">\", value: [\"$bound\"])\n",
    "    }\n",
    "}\n",
    "\"\"\"\n",
    "args = {\n",
    "    \"not_bound\": \"123\",\n",
    "}\n",
    "try:\n",
    "    execute(query, args)\n",
    "    assert(False)\n",
    "except QueryArgumentsError as e:\n",
    "    print(e)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.1"
  },
  "vscode": {
   "interpreter": {
    "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
